namespace Velocity4Net.Runtime.Parse.AST
{
    using System;
    using Parser = Velocity4Net.Runtime.Parse.Parser;
    using MethodInvocationException = Velocity4Net.Errors.MethodInvocationException;
    using InternalContextAdapter = Velocity4Net.Ctx.InternalContextAdapter;

    /**
     *  Handles <code>arg1  != arg2</code>
     *
     *  This operator requires that the LHS and RHS are both of the
     *  same Class OR both are subclasses of java.lang.Number
     *
     *  @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a>
     *  @author <a href="mailto:pero@antaramusic.de">Peter Romianowski</a>
     */
    public class ASTNENode : SimpleNode
    {
        public ASTNENode(int id) : base(id) { }

        public ASTNENode(Parser p, int id) : base(p, id) { }
        /**
         * @see org.apache.velocity.runtime.parser.node.SimpleNode#evaluate(org.apache.velocity.context.InternalContextAdapter)
         */
        public override bool Evaluate(InternalContextAdapter context)
        {
            Object left = jjtGetChild(0).GetValue(context);
            Object right = jjtGetChild(1).GetValue(context);

            /*
             *  convert to Number if applicable
             */
            try
            {
                decimal l = Convert.ToDecimal(left);
                decimal r = Convert.ToDecimal(right);
                return l != r;
            }
            catch
            {
            }
            //if (left is TemplateNumber)
            //{
            //   left = ( (TemplateNumber) left).getAsNumber();
            //}
            //if (right instanceof TemplateNumber)
            //{
            //   right = ( (TemplateNumber) right).getAsNumber();
            //}

            /*
             * If comparing Numbers we do not care about the Class.
             */
            //if (left instanceof Number && right instanceof Number)
            //{
            //     return MathUtils.compare ( (Number)left,(Number)right) != 0;
            //}

            /**
             * if both are not null, then assume that if one class
             * is a subclass of the other that we should use the equals operator
             */
            if (left != null && right != null &&
                (left.GetType().IsAssignableFrom(right.GetType()) ||
                     right.GetType().IsAssignableFrom(left.GetType())))
            {
                return !left.Equals(right);
            }

            /*
             * Ok, time to compare string values
             */
            left = (left == null) ? null : left.ToString();
            right = (right == null) ? null : right.ToString();

            if (left == null && right == null)
            {
                if (log.isDebugEnabled())
                {
                    log.debug("Both right (" + getLiteral(false) + " and left "
                              + getLiteral(true) + " sides of '!=' operation returned null."
                              + "If references, they may not be in the context."
                              + GetLocation(context));
                }
                return false;
            }
            else if (left == null || right == null)
            {
                if (log.isDebugEnabled())
                {
                    log.debug((left == null ? "Left" : "Right")
                            + " side (" + getLiteral(left == null)
                            + ") of '!=' operation has null value. If it is a "
                            + "reference, it may not be in the context or its "
                            + "toString() returned null. " + GetLocation(context));

                }
                return true;
            }
            else
            {
                return !left.Equals(right);
            }
        }

        private String getLiteral(bool left)
        {
            return jjtGetChild(left ? 0 : 1).Literal();
        }

        /**
         * @see org.apache.velocity.runtime.parser.node.SimpleNode#value(org.apache.velocity.context.InternalContextAdapter)
         */
        public override Object GetValue(InternalContextAdapter context)
        {
            bool val = Evaluate(context);

            return val;
        }

    }

}
